#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#include <time.h>

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>

#include "port_comm.h"

int initCamera(int camera);
int startSending(PortComm *commClient);
cv::Mat toGrey(cv::Mat mat);
//void signal_handler(int sig);
void printUsage();

cv::VideoCapture capture;
bool inter = false;

int main(int argc, char *argv[])
{
    if (argc != 3 && argc != 4)
    {
        printUsage();
        return 1;
    }
  
    /*// Register signal handler
    if(signal(SIGINT, signal_handler) == SIG_ERR){
        fprintf(stderr, "Unable to bind handler.\n");
        return 1;
    }*/

    char* host = argv[1];
    int portno = atoi(argv[2]);
    PortComm commClient = PortComm(host, portno, PortComm::CLIENT);
    if(!commClient.isValid() || inter)
    {
        fprintf(stderr, "Unable to init connection.\n");
        return 1;
    }
    printf("Init Connection complete.\n");

    int camera = 0;
    if(argc == 4)
    {
        camera = atoi(argv[3]);
    }
    if(initCamera(camera) != 0 || inter)
    {
        fprintf(stderr, "Unable to init camera.\n");
    }
    printf("Init Camera complete.\n");

    printf("Starting sending.\n");
    startSending(&commClient);
  
    return 0;
}


int initCamera(int camera)
{
  
    //Init camera
    capture = cv::VideoCapture(camera);
    if(!capture.isOpened()) {
        fprintf(stderr, "Unable to init webcam.\n");
        return 1;
    }

    //Init camera succesful
    return 0;
}

int startSending(PortComm *commClient)
{
    cv::vector<int> params;
    params.push_back(CV_IMWRITE_JPEG_QUALITY);
    params.push_back(95); // Set Quality
        
    cv::Mat frame;
    while(!inter)
    {
        int size;
        unsigned char *mode;
        commClient->read_port(&mode, &size);
        int quality = *mode % 101;
        bool grey = *mode > 100;
        delete []mode;

        //Grab into a Mat
        if(!capture.read(frame))
        {
            continue;
        }

        if(grey)
        {
            frame = toGrey(frame);
        }
        params[1] = quality;

        //Move to buf to encode to jpg
        cv::vector<uchar> buf;
        if(!imencode("*.jpg", frame, buf, params))
        {
            fprintf(stderr, "Unable to encode image.\n");
            break;
        }

        //Change to char array to send
        char *message = new char[buf.size()];
        for(int i = 0; i < (int)buf.size(); i++)
        {
            message[i] = (char)buf[i];
        }
        commClient->write_port((unsigned char*) message, (int)buf.size());
        delete []message;
    }

    return 0;
}

cv::Mat toGrey(cv::Mat mat)
{
    cv::Mat ans(mat.rows, mat.cols, CV_8UC1);

    cv::vector<cv::Mat> plane;
    split(mat, plane);

    for(int r = 0; r < mat.rows; r++)
    {
        for(int c = 0; c < mat.cols; c++)
        {
            int sum = 0;
            for(int n = 0; n < (int)plane.size(); n++)
            {
                sum += plane[n].at<uchar>(r, c);
            }
            ans.at<uchar>(r, c) = (sum / (int)plane.size());
        }
    }

    return ans;
}

/*void signal_handler(int sig)
{
    printf("Interrupt Caught.\n");
    inter = true;
}*/

void printUsage()
{
    printf("Usage: camera <host> <port> [<camera>]\n");
    return;
}

